#pragma once
#include <memory>
#include "Socket.hpp"
#include <iostream>
#include "Log.hpp"
#include <string>
#include "Epoller.hpp"
#include <sys/epoll.h>

using namespace EpollModuo;


class EpollServer{
    
static const int gmaxevents = 1024;
static const int backlog = 16;

public:
    EpollServer(int port):_port(port),_listensock(new TcpSocket()),_isrunning(false),_epoller(new  Epoller)
    {}

    ~EpollServer(){}

    bool InitServer()
    {
        _listensock->BuildListenSocketMethod(_port,backlog);
        lg.LogMessage(Info,"init socket success,listensock is %d\n",_listensock->GetSockfd());


        _epoller->InitEpoller();
        lg.LogMessage(Info," Init epoll success\n");

        _epoller->AddEvent(_listensock->GetSockfd(),EPOLLIN);
        
        return true;
    }

    bool Accept (std::string* ip,uint16_t* port)
    {
        int  fd = _listensock->AcceptConnection(ip,port);//返回-1表示错误，正确返回连接的文件描述符
        if(fd < 0)
        {
            lg.LogMessage(Warning,"accept error\n");
            return false;
        }
        else
        {
            _epoller->AddEvent(fd,EPOLLIN);
            return true;
        }
    }

    int Recver(int fd,string* out)
    {
        char buf[1024];
        int n = recv(fd,buf,sizeof(buf),0);
        if(n > 0) *out = buf;
        return n;
    }
    void HandlerEvent(int n)//处理方法
    {
        lg.LogMessage( Debug,"%d 个events 已经就绪了\n",n);

        for(int i = 0 ; i < gmaxevents;i++)
        {
            int sockfd = _recv[i].data.fd;//获取就绪队列中数据的文件描述符
            uint32_t events = _recv[i].events;//获取就绪队列的就绪事件
            if(events & EPOLLIN)
            {
                if(sockfd == _listensock->GetSockfd())//连接事件就绪
                {
                    //获取新链接
                    string clientip;
                    uint16_t clientport;
                    if(!Accept(&clientip,&clientport))
                    {
                        continue;//下一个
                    }
                    lg.LogMessage(Info,"accept client success, client[%s:%d]\n",clientip.c_str(),clientport);
                }
                else//normal sockfd
                {
                    string message;
                    int n = Recver(sockfd,&message);
                    if(n > 0)//读取成功
                    {
                        //将这个message变成一个字符串，减去协议中的\r\n大小，也就是留出位置给他，代表了他们的存在
                        // message.resize(message.size() - strlen("\r\n"));

                        //获取读取到信息,打印查看
                        std::cout << "sockfd："<< sockfd << ",message:  "<< message << std::endl; 

                        //将要发送的信息发给客户端
                        string echo_meesage = "echo_message:" + message + "\r\n";
                        
                        send(sockfd,echo_meesage.c_str(),echo_meesage.size(),0);
                    }
                    else{//读取失败分为两种，因为他们都需要关闭Event所以并在一起
                        if(n == 0){
                            lg.LogMessage(Info,"clinet %d close\n",sockfd);
                        }
                        else{
                            lg.LogMessage(Info,"client recv %d error\n",sockfd);
                        }
                        _epoller->DelEvent(sockfd);
                        close(sockfd);//关闭epoll模型（由文件描述符管理）
                    }
                }
            }
        }
    }
    void loop()
    {
        _isrunning = true;
        while(_isrunning)
        {
            int timeout = -1;
            int n = _epoller->Wait(_recv,gmaxevents,timeout);//检测查看是否有事件 就绪
            switch (n)
            {
            case 0:
                lg.LogMessage(Debug,"timeout...超时\n");
                break;
            case -1:
                lg.LogMessage(Error,"epoll wait failed\n");
                break;
            default://当>0时就表示 有 事件就绪了
                lg.LogMessage(Info," event happend... \n");
                HandlerEvent(n);//处理就绪事件
                break;
            }
        }
        _isrunning = false;
    }

private:
    int _port;
    bool _isrunning;
    std::unique_ptr<Socket> _listensock;
    std::unique_ptr<Epoller> _epoller;
    struct epoll_event _recv[gmaxevents];
};